package compilers.AST.types;

import compilers.AST.Node;
import compilers.exceptions.SemanticalException;
import compilers.symbolTable.SymbolTableElement;
import compilers.symbolTable.SymbolTableScope;

public class TypeSpecifier extends Node {
	
	public final static int CHAR = 1;
	public final static int INTEGER = 2;
	public final static int FLOAT = 3;
	public final static int VOID = 4;
	public final static int BOOLEAN = 5;
	
	private int fType;
	private String fCustomTypeName;

	public TypeSpecifier(int type) {
		fType = type;
		fCustomTypeName = "";
	}
	
	public TypeSpecifier(int type, int lineNr) {
		super(lineNr);
		fType = type;
		fCustomTypeName = "";
	}
	
	public TypeSpecifier(String customTypeName, int lineNr) {
		super(lineNr);
		fType = 0;
		fCustomTypeName = customTypeName;
	}
	
	public void print(int identLevel) {
		println(identLevel, "TypeSpecifier");
		println(identLevel+1, getTypeName());
	}
	
	public void checkSemantics(SymbolTableScope currentScope)  throws SemanticalException  {
		if (fType == 0) {
			if (currentScope.getElement(fCustomTypeName, fNodeId) == null) {
				throw new SemanticalException("The typename '" + fCustomTypeName + "' is not declared.", fLineNr);
			}
		}
	}
	
	public int getType(SymbolTableScope currentScope) {
		if (fType > 0) {
			return fType;
		} else {
			SymbolTableElement typeElement = currentScope.getElement(fCustomTypeName, fNodeId);
			return typeElement.getType().getType(currentScope);
		}
	}
	
	public String getTypeName() {
		if (fType > 0) {
			String typeName = "";
			switch(fType) {
				case CHAR:
					typeName = "char";
					break;
				case INTEGER:
					typeName = "int";
					break;
				case FLOAT:
					typeName = "float";
					break;
				case VOID:
					typeName = "void";
					break;
				case BOOLEAN:
					typeName = "boolean";
					break;
			}
			return typeName;
		} else {
			return fCustomTypeName;
		}
	}
	
	public char getPType(SymbolTableScope currentScope) {
		switch(this.getType(currentScope)) {
			case CHAR:
				return 'c';
			case INTEGER:
				return 'i';
			case FLOAT:
				return 'r';
			case BOOLEAN:
				return 'b';
			default:
				return ' ';
		}
	}
	
	public static char getPType(int type) {
		switch(type) {
			case CHAR:
				return 'c';
			case INTEGER:
				return 'i';
			case FLOAT:
				return 'r';
			case BOOLEAN:
				return 'b';
			default:
				return ' ';
		}
	}
	
	public static String getType(int type) {
		switch(type) {
			case CHAR:
				return "boolean";
			case INTEGER:
				return "int";
			case FLOAT:
				return "float";
			case BOOLEAN:
				return "boolean";
			case VOID:
				return "void";
		}
		return "";
	}
}
